import QuickHull from '../algorithms/quickHull'
import moment from "moment/moment";

const quickHull = QuickHull.quickHull;
function sqr(x) {
    return x * x;
}

function dist2(a, b) {
    return sqr(a.x - b.x) + sqr(a.y - b.y);
}

function det(a, b) {
    return a.x * b.y - a.y * b.x;
}

function getVerticalIntersectionPoint(pa, va, wa) {
    let l2 = dist2(va, wa);
    let t = ((pa.x - va.x) * (wa.x - va.x) + (pa.y - va.y) * (wa.y - va.y)) / l2;
    t = Math.max(0.0, Math.min(1.0, t));
    return { x: va.x + t * (wa.x - va.x), y: va.y + t * (wa.y - va.y) };
}

let MODE = 1;
let lastLines = [];
var strategyLines = [];
var weeklyData = [];
var monthlyData = [];
const genLongPeriodData = function(dailyData){

    for(const line of dailyData){
        var time = moment.unix(line.time / 1000);
        var startOfWeek = time.clone().startOf('isoWeek').unix() * 1000;
        var startOfMonth = time.clone().startOf('month').unix() * 1000;

        if(weeklyData.length == 0 || weeklyData[weeklyData.length-1].timestamp != startOfWeek) {
            weeklyData.push({
                open: line.open,
                close: line.close,
                high: line.high,
                low: line.low,
                timestamp: startOfWeek,
                volume: line.volume,
                amount: line.amount
            })
        }
        weeklyData[weeklyData.length-1].close = line.close;
        weeklyData[weeklyData.length-1].high = Math.max(weeklyData[weeklyData.length-1].high, line.high);
        weeklyData[weeklyData.length-1].low = Math.min(weeklyData[weeklyData.length-1].low, line.low);
        weeklyData[weeklyData.length-1].volume += line.volume;
        weeklyData[weeklyData.length-1].amount += line.amount;

        if(monthlyData.length == 0 || monthlyData[monthlyData.length-1].timestamp != startOfMonth) {
            monthlyData.push({
                open: line.open,
                close: line.close,
                high: line.high,
                low: line.low,
                timestamp: startOfMonth,
                volume: line.volume,
                amount: line.amount
            })
        }
        monthlyData[monthlyData.length-1].close = line.close;
        monthlyData[monthlyData.length-1].high = Math.max(monthlyData[monthlyData.length-1].high, line.high);
        monthlyData[monthlyData.length-1].low = Math.min(monthlyData[monthlyData.length-1].low, line.low);
        monthlyData[monthlyData.length-1].volume += line.volume;
        monthlyData[monthlyData.length-1].amount += line.amount;

    }
    weeklyData[weeklyData.length-1].timestamp = dailyData[dailyData.length-1].timestamp;
    monthlyData[monthlyData.length-1].timestamp = dailyData[dailyData.length-1].timestamp;
}

function drawLine(data, chart, type) {

    let downcolor = 'green'
    if(type === "weekly"){
        downcolor = 'rgba(255,255,255,0.51)'
    }
    if(type === "monthly"){
        downcolor = 'rgba(255,255,255,0.51)'
    }

    let upcolor = 'red'
    if(type === "weekly"){
        upcolor = 'rgba(255,255,255,0.51)'
    }
    if(type === "monthly"){
        upcolor = 'rgba(255,255,255,0.51)'
    }

    let downline = "segment"
    let upline = "segment"


    let pfClose = data.map(c => c.close);
    let pfHigh = data.map(c => c.high);
    let pfLow = data.map(c => c.low);
    let DataLen = data.length;
    let mode = 1;
    let lastHighLine = [];
    let lastLowLine = [];

    let highHullPoints = [];
    let lowHullPoints = [];
    let stopIndex = 0;
    let RET = 0;

    for (let j = 0; j < DataLen; j++) {
        let index = j;
        let maxHigh = 0;
        for (let i = 0; i < DataLen; i++) {
            if (pfHigh[i] > maxHigh) {
                maxHigh = pfHigh[i];
            }
        }
        if (index > 0) {

            if (mode === 1) {
                if (DataLen > 0 && lastHighLine.length > 0) {
                    let intersection = getVerticalIntersectionPoint({ x: index, y: pfClose[index] }, lastHighLine[0], lastHighLine[1]);

                    if (pfClose[index] > intersection.y) {
                        if (j === DataLen - 1) {
                            RET = 2;
                        }

                        lastLines = [];
                        highHullPoints = [];
                        stopIndex = index - 1;
                        mode = 2;
                        // console.log("stopIndex: " + stopIndex + ", mode: " + mode);
                    }
                }
            } else if (mode === 2) {
                if (DataLen > 0 && lastLowLine.length > 0) {
                    let intersection = getVerticalIntersectionPoint({ x: index, y: pfClose[index] }, lastLowLine[0], lastLowLine[1]);

                    if (pfClose[index] < intersection.y) {
                        if (j === DataLen - 1) {
                            RET = 1;
                        }
                        lastLines = [];
                        lowHullPoints = [];
                        stopIndex = index - 1;
                        mode = 1;
                        // console.log("stopIndex: " + stopIndex + ", mode: " + mode);
                    }
                }
            }

            let highPoints = [];
            let lowPoints = [];
            for(var shapeId of lastLines){
                // console.log("removing", shapeId)
                chart.removeOverlay(shapeId);
            }
            if (mode === 1) {
                highPoints.push({ x: stopIndex, y: -1000 });
                for (let i = stopIndex; i <= index; i++) {
                    highPoints.push({ x: i, y: pfHigh[i] });
                }
                highPoints.push({ x: index, y: -1000 });
                highHullPoints = quickHull(highPoints.map(c=>[c.x, c.y]));
                highHullPoints = highHullPoints.filter(p => p.y !== -1000);

                highHullPoints.sort((a, b) => {
                    if (a.x === b.x) {
                        return a.y - b.y;
                    }
                    return a.x - b.x;
                });

                for (var i = 0; i < highHullPoints.length - 1; i++) {
                    var hpoint = highHullPoints[i];
                    var next = i + 1;
                    if (next >= highHullPoints.length) {
                        next = 0;
                    }
                    var npoint = highHullPoints[next];
                    if (npoint.y == -1000 || hpoint.y == -1000) {
                        continue;
                    }
                    var line = (chart.createOverlay({
                        name: 'segment',
                        points: [
                            {timestamp: data[hpoint.x].timestamp, value: hpoint.y},
                            {timestamp: data[npoint.x].timestamp, value: npoint.y},
                        ],
                        styles: {
                            line: {
                                color: downcolor,
                                size: 3,
                            },
                        },
                        lock: false,
                        mode: 'strong_magnet',
                        data: 'xxxxxxxx',
                    }))
                    lastLines.push(line);
                    strategyLines.push(line);

                }
                lastHighLine = highHullPoints.slice(-2);
            } else {
                lowPoints.push({ x: stopIndex, y: 100000 });
                for (let i = stopIndex; i <= index; i++) {
                    lowPoints.push({ x: i, y: pfLow[i] });
                }
                lowPoints.push({ x: index, y: 100000 });
                lowHullPoints = quickHull(lowPoints.map(c=>[c.x, c.y]));
                lowHullPoints = lowHullPoints.filter(p => p.y !== 100000);

                lowHullPoints.sort((a, b) => {
                    if (a.x === b.x) {
                        return a.y - b.y;
                    }
                    return a.x - b.x;
                });

                for (var i = 0; i < lowHullPoints.length - 1; i++) {
                    var hpoint = lowHullPoints[i];
                    var next = i + 1;
                    if (next >= lowHullPoints.length) {
                        next = 0;
                    }
                    var npoint = lowHullPoints[next];
                    if (npoint.y == 100000 || hpoint[1] == 100000) {
                        continue;
                    }
                    var line = (chart.createOverlay({
                        name: 'segment',
                        points: [
                            {timestamp: data[hpoint.x].timestamp, value: hpoint.y},
                            {timestamp: data[npoint.x].timestamp, value: npoint.y},
                        ],
                        styles: {
                            line: {
                                color: upcolor,
                                size: 3,
                            },
                        },
                        lock: false,
                        mode: 'strong_magnet',
                        data: 'xxxxxxxx',
                    }));
                    lastLines.push(line);
                    strategyLines.push(line);
                }

                lastLowLine = lowHullPoints.slice(-2);
            }
        }
    }
    MODE = mode;
    return RET;
}
function update(chart, data){
    // console.log("?????", data)
    genLongPeriodData(data);
    drawLine(data, chart);
    // lastLines = [];
    // drawLine(weeklyData, chart, "weekly");
    // lastLines = [];
    // drawLine(monthlyData, chart, "monthly");
}

const reset = (chart) => {
    MODE = 1;
    for(var shapeId of strategyLines){
        // console.log("removing", shapeId)
        chart.removeOverlay(shapeId);
    }
    strategyLines = [];
    lastLines = [];
    weeklyData = [];
    monthlyData = [];
}

const comment = props => {
    return <div>未提供说明</div>
}

// Tools 已移除，HULL 仅作为指标使用，不在策略列表中显示
// const Tools = (props) => null;

export default {update, name: "HULL", comment, indicator: false, reset};
